using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using EventBehaviorTree;
using System;
using PropertySystem;

public class MainRole : SingletonMonoBehaviour<MainRole>
{
    private Health _health;
    public float _speed;
    public float _jumpForce;
    public LayerMask _groundLayer;

    private Rigidbody2D _RB;
    private Vector2 _direction;
    private bool _isJumpCommand;

    private RootNode _currentBehavior;
    private RootNode _baseMove;
    private RootNode _skillA;
    private RootNode _skill_Dash;

    private void Awake() { INI_Singleton(); }

    void Start()
    {
        _RB = GetComponent<Rigidbody2D>();
        SetBaseMove();
        SetSkillFloat();
        SetSkillDash();
        _currentBehavior = _baseMove;
        _currentBehavior.NodeEvent(NodeMessage.Start);

        InputManager.Instance.UpdateInputEvent(delegate (Vector2 vector2) { _direction = vector2; }, true);
        InputManager.Instance.UpdateInputEvent(GameplayKeyCode.UpArrow, InputActionPhase.Started, delegate { _isJumpCommand = true; }, true);
        InputManager.Instance.UpdateInputEvent(GameplayKeyCode.UpArrow, InputActionPhase.Canceled, delegate { _isJumpCommand = false; }, true);
        InputManager.Instance.UpdateInputEvent(GameplayKeyCode.O, InputActionPhase.Started,
            delegate
            {
                _currentBehavior.NodeEvent(NodeMessage.COMMAND_Stop);
                _currentBehavior = _skill_Dash;
                _currentBehavior.NodeEvent(NodeMessage.Start);
            }, true);
        InputManager.Instance.UpdateInputEvent(GameplayKeyCode.P, InputActionPhase.Started,
            delegate
            {
                _currentBehavior.NodeEvent(NodeMessage.COMMAND_Stop);
                _currentBehavior = _skillA;
                _currentBehavior.NodeEvent(NodeMessage.Start);
            }, true);
        _health = new Health();


    }

    void Update()
    {

    }

    private void SetBaseMove()
    {
        _baseMove = new RootNode();
        Sequencer sequencer = new Sequencer();
        AsyncSwitcher ground = new AsyncSwitcher(IsOnGround);
        AsyncSwitcher air = new AsyncSwitcher(IsInTheAir);
        Asynchronous airMove = new Asynchronous(XAxisMove);
        //Asynchronous airMove = new Asynchronous();
        AsyncSwitcher idle = new AsyncSwitcher(delegate { return true; });
        AsyncSwitcher interaction = new AsyncSwitcher();//skill judge
        Asynchronous walk = new Asynchronous(XAxisMove);
        AsyncSwitcher jump = new AsyncSwitcher(delegate { return _isJumpCommand; });
        InstantTask jumpAction = new InstantTask(Jump);

        _baseMove.SetKey();
        _baseMove.AddSubNode(sequencer);
        sequencer.AddSubNode(new InstantTask(ResetGravity), ground, air);
        ground.AddSubNode(idle, interaction);
        air.AddSubNode(airMove);
        idle.AddSubNode(walk, jump);
        jump.AddSubNode(jumpAction);
        _baseMove.SetCoroutineStarter(this);
        _baseMove.NodeEvent(NodeMessage.Start);
    }

    private void SetSkillFloat()
    {
        _skillA = new RootNode();
        Sequencer sequencer = new Sequencer();
        CountdownSequencer jumpMove = new CountdownSequencer(25, "Busy");
        CountdownSequencer airMove = new CountdownSequencer(60, "Busy");
        AsyncSwitcher ground = new AsyncSwitcher(IsOnGround);
        _skillA.SetKey();
        _skillA.AddSubNode(sequencer);
        sequencer.AddSubNode(new InstantTask(Jump),
            jumpMove,
            new InstantTask(NoGravity),
            new InstantTask(Stop),
            airMove,
            new InstantTask(ResetGravity),
            ground);
        jumpMove.AddSubNode(new Asynchronous(XAxisMove));
        airMove.AddSubNode(new Asynchronous(XAxisMove));
        ground.AddSubNode(new InstantTask(ResetBaseMove), new InstantTask("Shutdown", _skillA));
        _skillA.SetCoroutineStarter(this);
    }

    private void SetSkillDash()
    {
        _skill_Dash = new RootNode();
        _skill_Dash.SetKey();
        Sequencer sequencer = new Sequencer();
        _skill_Dash.AddSubNode(sequencer);
        sequencer.AddSubNode(new InstantTask(Stop),
            new InstantTask(NoGravity),
            new InstantTask(Dash),
            new CountdownSequencer(15, "Delay"),
            new InstantTask(ResetGravity),
            new InstantTask(ResetBaseMove),
            new InstantTask(Stop, "Shutdown", _skill_Dash));
        _skill_Dash.SetCoroutineStarter(this);
    }

    private void ResetBaseMove()
    {
        _currentBehavior.NodeEvent(NodeMessage.COMMAND_Stop);
        _currentBehavior = _baseMove;
        _currentBehavior.NodeEvent(NodeMessage.Start);
    }

    private void Dash()
    {
        Vector2 vector2 = new Vector2(gameObject.transform.localScale.x == 1 ? 1 : -1, 0);
        _RB.AddForce(vector2 * _jumpForce, ForceMode2D.Impulse);
    }

    private void XAxisMove()
    {
        if (_direction.x == 0)
        {
            _RB.velocity = new Vector3(0, _RB.velocity.y, 0);
            return;
        }
        _RB.velocity = new Vector3(Math.Abs(_direction.x) / _direction.x * _speed, _RB.velocity.y, 0);
        gameObject.transform.localScale = new Vector3(Math.Abs(_direction.x) / _direction.x, 1, 1);//flip
    }

    private void Jump()
    {
        _RB.AddForce(transform.up * _jumpForce, ForceMode2D.Impulse);
        _isJumpCommand = false;
    }

    private bool IsOnGround()
    {
        return Physics2D.OverlapArea((Vector2)transform.position + new Vector2(-0.4f, -0.6f), (Vector2)transform.position + new Vector2(0.4f, -0.7f), _groundLayer);
    }
    private bool IsInTheAir() { return !IsOnGround(); }

    private void NoGravity() { _RB.gravityScale = 0; }
    private void ResetGravity() { _RB.gravityScale = 6; }
    private void Stop() { _RB.velocity = Vector3.zero; }
}
